{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# This script processing images and training your own  face classifier."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python2.7/dist-packages/matplotlib/font_manager.py:273: UserWarning: Matplotlib is building the font cache using fc-list. This may take a moment.\n",
      "  warnings.warn('Matplotlib is building the font cache using fc-list. This may take a moment.')\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Populating the interactive namespace from numpy and matplotlib\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python2.7/dist-packages/sklearn/cross_validation.py:44: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.\n",
      "  \"This module will be removed in 0.20.\", DeprecationWarning)\n",
      "/usr/local/lib/python2.7/dist-packages/IPython/core/magics/pylab.py:161: UserWarning: pylab import has clobbered these variables: ['copy']\n",
      "`%matplotlib` prevents importing * from pylab and numpy\n",
      "  \"\\n`%matplotlib` prevents importing * from pylab and numpy\"\n"
     ]
    }
   ],
   "source": [
    "\n",
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "import cv2\n",
    "\n",
    "import os\n",
    "from os.path import join as pjoin\n",
    "import sys\n",
    "import copy\n",
    "import detect_face\n",
    "import nn4 as network\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "\n",
    "import sklearn\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn import metrics  \n",
    "from sklearn.externals import joblib\n",
    "\n",
    "%pylab inline\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "#face detection parameters\n",
    "minsize = 20 # minimum size of face\n",
    "threshold = [ 0.6, 0.7, 0.7 ]  # three steps's threshold\n",
    "factor = 0.709 # scale factor\n",
    "\n",
    "#facenet embedding parameters\n",
    "\n",
    "model_dir='./model_check_point/model.ckpt-500000'#\"Directory containing the graph definition and checkpoint files.\")\n",
    "model_def= 'models.nn4'  # \"Points to a module containing the definition of the inference graph.\")\n",
    "image_size=96 #\"Image size (height, width) in pixels.\"\n",
    "pool_type='MAX' #\"The type of pooling to use for some of the inception layers {'MAX', 'L2'}.\n",
    "use_lrn=False #\"Enables Local Response Normalization after the first layers of the inception network.\"\n",
    "seed=42,# \"Random seed.\"\n",
    "batch_size= None # \"Number of images to process in a batch.\"\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating networks and loading parameters\n"
     ]
    }
   ],
   "source": [
    "#建立人脸检测模型，加载参数\n",
    "print('Creating networks and loading parameters')\n",
    "gpu_memory_fraction=1.0\n",
    "with tf.Graph().as_default():\n",
    "    gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=gpu_memory_fraction)\n",
    "    sess = tf.Session(config=tf.ConfigProto(gpu_options=gpu_options, log_device_placement=False))\n",
    "    with sess.as_default():\n",
    "        pnet, rnet, onet = detect_face.create_mtcnn(sess, './model_check_point/')\n",
    "        \n",
    "      "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "建立facenet embedding模型\n",
      "name =  incept3a\n",
      "inputSize =  192\n",
      "kernelSize = {3,5}\n",
      "kernelStride = {1,1}\n",
      "outputSize = {128,32}\n",
      "reduceSize = {96,16,32,64}\n",
      "pooling = {MAX, 3, 3, 1, 1}\n",
      "outputSize =  256\n",
      "\n",
      "name =  incept3b\n",
      "inputSize =  256\n",
      "kernelSize = {3,5}\n",
      "kernelStride = {1,1}\n",
      "outputSize = {128,64}\n",
      "reduceSize = {96,32,64,64}\n",
      "pooling = {MAX, 3, 3, 1, 1}\n",
      "outputSize =  320\n",
      "\n",
      "name =  incept3c\n",
      "inputSize =  320\n",
      "kernelSize = {3,5}\n",
      "kernelStride = {2,2}\n",
      "outputSize = {256,64}\n",
      "reduceSize = {128,32,0,0}\n",
      "pooling = {MAX, 3, 3, 2, 2}\n",
      "outputSize =  640\n",
      "\n",
      "name =  incept4a\n",
      "inputSize =  640\n",
      "kernelSize = {3,5}\n",
      "kernelStride = {1,1}\n",
      "outputSize = {192,64}\n",
      "reduceSize = {96,32,128,256}\n",
      "pooling = {MAX, 3, 3, 1, 1}\n",
      "outputSize =  640\n",
      "\n",
      "name =  incept4b\n",
      "inputSize =  640\n",
      "kernelSize = {3,5}\n",
      "kernelStride = {1,1}\n",
      "outputSize = {224,64}\n",
      "reduceSize = {112,32,128,224}\n",
      "pooling = {MAX, 3, 3, 1, 1}\n",
      "outputSize =  640\n",
      "\n",
      "name =  incept4c\n",
      "inputSize =  640\n",
      "kernelSize = {3,5}\n",
      "kernelStride = {1,1}\n",
      "outputSize = {256,64}\n",
      "reduceSize = {128,32,128,192}\n",
      "pooling = {MAX, 3, 3, 1, 1}\n",
      "outputSize =  640\n",
      "\n",
      "name =  incept4d\n",
      "inputSize =  640\n",
      "kernelSize = {3,5}\n",
      "kernelStride = {1,1}\n",
      "outputSize = {288,64}\n",
      "reduceSize = {144,32,128,160}\n",
      "pooling = {MAX, 3, 3, 1, 1}\n",
      "outputSize =  640\n",
      "\n",
      "name =  incept4e\n",
      "inputSize =  640\n",
      "kernelSize = {3,5}\n",
      "kernelStride = {2,2}\n",
      "outputSize = {256,128}\n",
      "reduceSize = {160,64,0,0}\n",
      "pooling = {MAX, 3, 3, 2, 2}\n",
      "outputSize =  1024\n",
      "\n",
      "name =  incept5a\n",
      "inputSize =  1024\n",
      "kernelSize = {3,5}\n",
      "kernelStride = {1,1}\n",
      "outputSize = {384,0}\n",
      "reduceSize = {192,0,128,384}\n",
      "pooling = {MAX, 3, 3, 1, 1}\n",
      "outputSize =  896\n",
      "\n",
      "name =  incept5b\n",
      "inputSize =  896\n",
      "kernelSize = {3,5}\n",
      "kernelStride = {1,1}\n",
      "outputSize = {384,0}\n",
      "reduceSize = {192,0,128,384}\n",
      "pooling = {MAX, 3, 3, 1, 1}\n",
      "outputSize =  896\n",
      "\n",
      "facenet embedding模型建立完毕\n"
     ]
    }
   ],
   "source": [
    "#建立facenet embedding模型\n",
    "print('建立facenet embedding模型')\n",
    "tf.Graph().as_default()\n",
    "sess = tf.Session()\n",
    "images_placeholder = tf.placeholder(tf.float32, shape=(batch_size, \n",
    "                                                       image_size, \n",
    "                                                       image_size, 3), name='input')\n",
    "\n",
    "phase_train_placeholder = tf.placeholder(tf.bool, name='phase_train')\n",
    "\n",
    "\n",
    "\n",
    "embeddings = network.inference(images_placeholder, pool_type, \n",
    "                               use_lrn, \n",
    "                               1.0, \n",
    "                               phase_train=phase_train_placeholder)\n",
    "\n",
    "\n",
    "\n",
    "ema = tf.train.ExponentialMovingAverage(1.0)\n",
    "saver = tf.train.Saver(ema.variables_to_restore())\n",
    "\n",
    "model_checkpoint_path='./model_check_point/model-20160506.ckpt-500000'\n",
    "\n",
    "saver.restore(sess, model_checkpoint_path)\n",
    "print('facenet embedding模型建立完毕')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "# reading training images from train folder\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "###### train_dir containing one subdirectory per image class \n",
    "#should like this:\n",
    "#-->train_dir:\n",
    "#     --->pic_me:\n",
    "#            me1.jpg\n",
    "#            me2.jpg\n",
    "#            ...\n",
    "#     --->pic_others:\n",
    "#           other1.jpg\n",
    "#            other2.jpg\n",
    "#            ...\n",
    "data_dir='~/train_dir/'#your own train folder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def to_rgb(img):\n",
    "    w, h = img.shape\n",
    "    ret = np.empty((w, h, 3), dtype=np.uint8)\n",
    "    ret[:, :, 0] = ret[:, :, 1] = ret[:, :, 2] = img\n",
    "    return ret\n",
    "\n",
    "def read_img(person_dir,f):\n",
    "    img=cv2.imread(pjoin(person_dir, f))\n",
    "    \n",
    "    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)\n",
    "        \n",
    "    if gray.ndim == 2:\n",
    "        img = to_rgb(gray)\n",
    "    return img\n",
    "\n",
    "def load_data(data_dir):\n",
    "    data = {}\n",
    "    pics_ctr = 0\n",
    "    for guy in os.listdir(data_dir):\n",
    "        person_dir = pjoin(data_dir, guy)\n",
    "        \n",
    "        curr_pics = [read_img(person_dir, f) for f in os.listdir(person_dir)]\n",
    "        \n",
    "     \n",
    "        \n",
    "        data[guy] = curr_pics\n",
    "        \n",
    "    return data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "foler:other,image numbers：70\n",
      "foler:video_guai,image numbers：137\n",
      "foler:video_me,image numbers：115\n"
     ]
    }
   ],
   "source": [
    "data=load_data(data_dir)\n",
    "keys=[]\n",
    "for key in data.iterkeys():\n",
    "    keys.append(key)\n",
    "    print('foler:{},image numbers：{}'.format(key,len(data[key])))\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "68\n",
      "145\n",
      "搞完了，样本数为：145\n"
     ]
    }
   ],
   "source": [
    "train_x=[]\n",
    "train_y=[]\n",
    "\n",
    "for x in data[keys[0]]:\n",
    "    bounding_boxes, _ = detect_face.detect_face(x, minsize, pnet, rnet, onet, threshold, factor)\n",
    "    nrof_faces = bounding_boxes.shape[0]#number of faces\n",
    "  \n",
    "    \n",
    "    \n",
    "    for face_position in bounding_boxes:\n",
    "        face_position=face_position.astype(int)\n",
    "        #print(face_position[0:4])\n",
    "        cv2.rectangle(x, (face_position[0], face_position[1]), (face_position[2], face_position[3]), (0, 255, 0), 2)\n",
    "        crop=x[face_position[1]:face_position[3],\n",
    "             face_position[0]:face_position[2],]\n",
    "    \n",
    "        crop = cv2.resize(crop, (96, 96), interpolation=cv2.INTER_CUBIC )\n",
    "\n",
    "        #print(crop.shape)\n",
    "        \n",
    "        crop_data=crop.reshape(-1,96,96,3)\n",
    "        #print(crop_data.shape)\n",
    "        \n",
    "        emb_data = sess.run([embeddings], \n",
    "                            feed_dict={images_placeholder: np.array(crop_data), phase_train_placeholder: False })[0]\n",
    "        \n",
    "        \n",
    "        train_x.append(emb_data)\n",
    "        train_y.append(0)\n",
    "print(len(train_x))\n",
    "\n",
    "\n",
    "\n",
    "for y in data[keys[1]]:\n",
    "    bounding_boxes, _ = detect_face.detect_face(y, minsize, pnet, rnet, \n",
    "                                                onet, threshold, factor)\n",
    "    nrof_faces = bounding_boxes.shape[0]#number of faces\n",
    "   \n",
    "    \n",
    "    \n",
    "    for face_position in bounding_boxes:\n",
    "        face_position=face_position.astype(int)\n",
    "        #print(face_position[0:4])\n",
    "        cv2.rectangle(y, (face_position[0], face_position[1]), (face_position[2], face_position[3]), (0, 255, 0), 2)\n",
    "        crop=y[face_position[1]:face_position[3],\n",
    "             face_position[0]:face_position[2],]\n",
    "    \n",
    "        crop = cv2.resize(crop, (96, 96), interpolation=cv2.INTER_CUBIC )\n",
    "\n",
    "        crop_data=crop.reshape(-1,96,96,3)\n",
    "        #print(crop_data.shape)\n",
    "        \n",
    "        emb_data = sess.run([embeddings], \n",
    "                            feed_dict={images_placeholder: np.array(crop_data), phase_train_placeholder: False })[0]\n",
    "        \n",
    "        \n",
    "        train_x.append(emb_data)\n",
    "        train_y.append(1)\n",
    "    \n",
    "\n",
    "print(len(train_x))\n",
    "print('搞完了，样本数为：{}'.format(len(train_x)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(145, 128)\n",
      "(145,)\n",
      "((101, 128), (101,), (44, 128), (44,))\n"
     ]
    }
   ],
   "source": [
    "#train/test split\n",
    "train_x=np.array(train_x)\n",
    "train_x=train_x.reshape(-1,128)\n",
    "train_y=np.array(train_y)\n",
    "print(train_x.shape)\n",
    "print(train_y.shape)\n",
    "\n",
    "\n",
    "X_train, X_test, y_train, y_test = train_test_split(train_x, train_y, test_size=.3, random_state=42)\n",
    "print(X_train.shape,y_train.shape,X_test.shape,y_test.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy: 100.00%\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "['./model_check_point/knn_classifier.model']"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "# KNN Classifier  \n",
    "def knn_classifier(train_x, train_y):  \n",
    "    from sklearn.neighbors import KNeighborsClassifier  \n",
    "    model = KNeighborsClassifier()  \n",
    "    model.fit(train_x, train_y)  \n",
    "    return model  \n",
    "\n",
    "classifiers = knn_classifier \n",
    "\n",
    "model = classifiers(X_train,y_train)  \n",
    "predict = model.predict(X_test)  \n",
    "\n",
    "accuracy = metrics.accuracy_score(y_test, predict)  \n",
    "print ('accuracy: %.2f%%' % (100 * accuracy)  ) \n",
    "  \n",
    "    \n",
    "#save model\n",
    "joblib.dump(model, './model_check_point/knn_classifier.model')\n",
    "#model = joblib.load('_2017_1_24_knn.model')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "accuracy: 100.00%\n"
     ]
    }
   ],
   "source": [
    "model = joblib.load('./model_check_point/knn_classifier.model')\n",
    "predict = model.predict(X_test) \n",
    "accuracy = metrics.accuracy_score(y_test, predict)  \n",
    "print ('accuracy: %.2f%%' % (100 * accuracy)  ) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
